/*
  Dokan : user-mode file system library for Windows

  Copyright (C) 2020 - 2025 Google, Inc.
  Copyright (C) 2015 - 2019 Adrien J. <liryna.stark@gmail.com> and Maxime C. <maxime@islog.com>
  Copyright (C) 2007 - 2011 Hiroki Asakawa <info@dokan-dev.net>

  http://dokan-dev.github.io

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "../../dokan/dokan.h"
#include "../../dokan/fileinfo.h"
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <winbase.h>

// Enable Long Paths on Windows 10 version 1607 and later by changing
// the OS configuration (see Microsoft own documentation for the steps)
// and rebuild the mirror with the following line uncommented.
#define WIN10_ENABLE_LONG_PATH
#ifdef WIN10_ENABLE_LONG_PATH
//dirty but should be enough
#define DOKAN_MAX_PATH 32768
#else
#define DOKAN_MAX_PATH MAX_PATH
#endif // DEBUG

BOOL g_UseStdErr;
BOOL g_DebugMode;
BOOL g_CaseSensitive;
BOOL g_HasSeSecurityPrivilege;
BOOL g_ImpersonateCallerUser;

static void DbgPrint(LPCWSTR format, ...) {
  if (g_DebugMode) {
    const WCHAR *outputString;
    WCHAR *buffer = NULL;
    size_t length;
    va_list argp;

    va_start(argp, format);
    length = _vscwprintf(format, argp) + 1;
    buffer = _malloca(length * sizeof(WCHAR));
    if (buffer) {
      vswprintf_s(buffer, length, format, argp);
      outputString = buffer;
    } else {
      outputString = format;
    }
    if (g_UseStdErr)
      fputws(outputString, stderr);
    else
      OutputDebugStringW(outputString);
    if (buffer)
      _freea(buffer);
    va_end(argp);
    if (g_UseStdErr)
      fflush(stderr);
  }
}

static WCHAR gRootDirectory[DOKAN_MAX_PATH] = L"C:";
static WCHAR gMountPoint[DOKAN_MAX_PATH] = L"M:\\";
static WCHAR gUNCName[DOKAN_MAX_PATH] = L"";
static WCHAR gVolumeName[MAX_PATH + 1] = L"DOKAN";

static void GetFilePath(PWCHAR filePath, ULONG numberOfElements,
                        LPCWSTR FileName) {
  wcsncpy_s(filePath, numberOfElements, gRootDirectory, wcslen(gRootDirectory));
  wcsncat_s(filePath, numberOfElements, FileName, wcslen(FileName));
}

static void PrintUserName(PDOKAN_FILE_INFO DokanFileInfo) {
  HANDLE handle;
  UCHAR buffer[1024];
  DWORD returnLength;
  WCHAR accountName[256];
  WCHAR domainName[256];
  DWORD accountLength = sizeof(accountName) / sizeof(WCHAR);
  DWORD domainLength = sizeof(domainName) / sizeof(WCHAR);
  PTOKEN_USER tokenUser;
  SID_NAME_USE snu;

  if (!g_DebugMode)
    return;

  handle = DokanOpenRequestorToken(DokanFileInfo);
  if (handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"  DokanOpenRequestorToken failed\n");
    return;
  }

  if (!GetTokenInformation(handle, TokenUser, buffer, sizeof(buffer),
                           &returnLength)) {
    DbgPrint(L"  GetTokenInformaiton failed: %d\n", GetLastError());
    CloseHandle(handle);
    return;
  }

  CloseHandle(handle);

  tokenUser = (PTOKEN_USER)buffer;
  if (!LookupAccountSid(NULL, tokenUser->User.Sid, accountName, &accountLength,
                        domainName, &domainLength, &snu)) {
    DbgPrint(L"  LookupAccountSid failed: %d\n", GetLastError());
    return;
  }

  DbgPrint(L"  AccountName: %s, DomainName: %s\n", accountName, domainName);
}

static BOOL AddSeSecurityNamePrivilege() {
  HANDLE token = 0;
  DbgPrint(
           L"## Attempting to add SE_SECURITY_NAME privilege to process token ##\n");
  DWORD err;
  LUID luid;
  if (!LookupPrivilegeValue(0, SE_SECURITY_NAME, &luid)) {
    err = GetLastError();
    if (err != ERROR_SUCCESS) {
      DbgPrint(L"  failed: Unable to lookup privilege value. error = %u\n",
               err);
      return FALSE;
    }
  }

  LUID_AND_ATTRIBUTES attr;
  attr.Attributes = SE_PRIVILEGE_ENABLED;
  attr.Luid = luid;

  TOKEN_PRIVILEGES priv;
  priv.PrivilegeCount = 1;
  priv.Privileges[0] = attr;

  if (!OpenProcessToken(GetCurrentProcess(),
                        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
    err = GetLastError();
    if (err != ERROR_SUCCESS) {
      DbgPrint(L"  failed: Unable obtain process token. error = %u\n", err);
      return FALSE;
    }
  }

  TOKEN_PRIVILEGES oldPriv;
  DWORD retSize;
  AdjustTokenPrivileges(token, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), &oldPriv,
                        &retSize);
  err = GetLastError();
  if (err != ERROR_SUCCESS) {
    DbgPrint(L"  failed: Unable to adjust token privileges: %u\n", err);
    CloseHandle(token);
    return FALSE;
  }

  BOOL privAlreadyPresent = FALSE;
  for (unsigned int i = 0; i < oldPriv.PrivilegeCount; i++) {
    if (oldPriv.Privileges[i].Luid.HighPart == luid.HighPart &&
        oldPriv.Privileges[i].Luid.LowPart == luid.LowPart) {
      privAlreadyPresent = TRUE;
      break;
    }
  }
  DbgPrint(privAlreadyPresent ? L"  success: privilege already present\n"
             : L"  success: privilege added\n");
  if (token)
    CloseHandle(token);
  return TRUE;
}

#define MirrorCheckFlag(val, flag)                                             \
  if (val & flag) {                                                            \
    DbgPrint(L"\t" L#flag L"\n");                                              \
  }

static NTSTATUS DOKAN_CALLBACK
MirrorCreateFile(LPCWSTR FileName, PDOKAN_IO_SECURITY_CONTEXT SecurityContext,
                 ACCESS_MASK DesiredAccess, ULONG FileAttributes,
                 ULONG ShareAccess, ULONG CreateDisposition,
                 ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle;
  DWORD fileAttr;
  NTSTATUS status = STATUS_SUCCESS;
  DWORD creationDisposition;
  DWORD fileAttributesAndFlags;
  DWORD error = 0;
  SECURITY_ATTRIBUTES securityAttrib;
  ACCESS_MASK genericDesiredAccess;
  // userTokenHandle is for Impersonate Caller User Option
  HANDLE userTokenHandle = INVALID_HANDLE_VALUE;

  securityAttrib.nLength = sizeof(securityAttrib);
  securityAttrib.lpSecurityDescriptor =
    SecurityContext->AccessState.SecurityDescriptor;
  securityAttrib.bInheritHandle = FALSE;

  DokanMapKernelToUserCreateFileFlags(
      DesiredAccess, FileAttributes, CreateOptions, CreateDisposition,
	  &genericDesiredAccess, &fileAttributesAndFlags, &creationDisposition);

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"CreateFile : %s\n", filePath);

  PrintUserName(DokanFileInfo);

  DbgPrint(L"\tShareMode = 0x%x\n", ShareAccess);

  MirrorCheckFlag(ShareAccess, FILE_SHARE_READ);
  MirrorCheckFlag(ShareAccess, FILE_SHARE_WRITE);
  MirrorCheckFlag(ShareAccess, FILE_SHARE_DELETE);

  DbgPrint(L"\tDesiredAccess = 0x%x\n", DesiredAccess);

  MirrorCheckFlag(DesiredAccess, GENERIC_READ);
  MirrorCheckFlag(DesiredAccess, GENERIC_WRITE);
  MirrorCheckFlag(DesiredAccess, GENERIC_EXECUTE);

  MirrorCheckFlag(DesiredAccess, DELETE);
  MirrorCheckFlag(DesiredAccess, FILE_READ_DATA);
  MirrorCheckFlag(DesiredAccess, FILE_READ_ATTRIBUTES);
  MirrorCheckFlag(DesiredAccess, FILE_READ_EA);
  MirrorCheckFlag(DesiredAccess, READ_CONTROL);
  MirrorCheckFlag(DesiredAccess, FILE_WRITE_DATA);
  MirrorCheckFlag(DesiredAccess, FILE_WRITE_ATTRIBUTES);
  MirrorCheckFlag(DesiredAccess, FILE_WRITE_EA);
  MirrorCheckFlag(DesiredAccess, FILE_APPEND_DATA);
  MirrorCheckFlag(DesiredAccess, WRITE_DAC);
  MirrorCheckFlag(DesiredAccess, WRITE_OWNER);
  MirrorCheckFlag(DesiredAccess, SYNCHRONIZE);
  MirrorCheckFlag(DesiredAccess, FILE_EXECUTE);
  MirrorCheckFlag(DesiredAccess, STANDARD_RIGHTS_READ);
  MirrorCheckFlag(DesiredAccess, STANDARD_RIGHTS_WRITE);
  MirrorCheckFlag(DesiredAccess, STANDARD_RIGHTS_EXECUTE);

  // When filePath is a directory, needs to change the flag so that the file can
  // be opened.
  fileAttr = GetFileAttributes(filePath);

  if (fileAttr != INVALID_FILE_ATTRIBUTES &&
      fileAttr & FILE_ATTRIBUTE_DIRECTORY) {
    if (CreateOptions & FILE_NON_DIRECTORY_FILE) {
      DbgPrint(L"\tCannot open a dir as a file\n");
      return STATUS_FILE_IS_A_DIRECTORY;
    }
    DokanFileInfo->IsDirectory = TRUE;
    // Needed by FindFirstFile to list files in it
    // TODO: use ReOpenFile in MirrorFindFiles to set share read temporary
    ShareAccess |= FILE_SHARE_READ;
  }

  DbgPrint(L"\tFlagsAndAttributes = 0x%x\n", fileAttributesAndFlags);

  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_ARCHIVE);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_COMPRESSED);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_DEVICE);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_DIRECTORY);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_ENCRYPTED);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_HIDDEN);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_INTEGRITY_STREAM);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_NORMAL);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_NO_SCRUB_DATA);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_OFFLINE);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_READONLY);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_REPARSE_POINT);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_SPARSE_FILE);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_SYSTEM);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_TEMPORARY);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_ATTRIBUTE_VIRTUAL);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_WRITE_THROUGH);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_OVERLAPPED);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_NO_BUFFERING);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_RANDOM_ACCESS);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_SEQUENTIAL_SCAN);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_DELETE_ON_CLOSE);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_BACKUP_SEMANTICS);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_POSIX_SEMANTICS);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_OPEN_REPARSE_POINT);
  MirrorCheckFlag(fileAttributesAndFlags, FILE_FLAG_OPEN_NO_RECALL);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_ANONYMOUS);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_IDENTIFICATION);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_IMPERSONATION);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_DELEGATION);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_CONTEXT_TRACKING);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_EFFECTIVE_ONLY);
  MirrorCheckFlag(fileAttributesAndFlags, SECURITY_SQOS_PRESENT);

  if (g_CaseSensitive)
    fileAttributesAndFlags |= FILE_FLAG_POSIX_SEMANTICS;

  if (creationDisposition == CREATE_NEW) {
    DbgPrint(L"\tCREATE_NEW\n");
  } else if (creationDisposition == OPEN_ALWAYS) {
    DbgPrint(L"\tOPEN_ALWAYS\n");
  } else if (creationDisposition == CREATE_ALWAYS) {
    DbgPrint(L"\tCREATE_ALWAYS\n");
  } else if (creationDisposition == OPEN_EXISTING) {
    DbgPrint(L"\tOPEN_EXISTING\n");
  } else if (creationDisposition == TRUNCATE_EXISTING) {
    DbgPrint(L"\tTRUNCATE_EXISTING\n");
  } else {
    DbgPrint(L"\tUNKNOWN creationDisposition!\n");
  }

  if (g_ImpersonateCallerUser) {
    userTokenHandle = DokanOpenRequestorToken(DokanFileInfo);

    if (userTokenHandle == INVALID_HANDLE_VALUE) {
      DbgPrint(L"  DokanOpenRequestorToken failed\n");
      // Should we return some error?
    }
  }

  if (DokanFileInfo->IsDirectory) {
    // It is a create directory request

    if (creationDisposition == CREATE_NEW ||
        creationDisposition == OPEN_ALWAYS) {

      if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
        // if g_ImpersonateCallerUser option is on, call the ImpersonateLoggedOnUser function.
        if (!ImpersonateLoggedOnUser(userTokenHandle)) {
          // handle the error if failed to impersonate
          DbgPrint(L"\tImpersonateLoggedOnUser failed.\n");
        }
      }

      // We create folder
      if (!CreateDirectory(filePath, &securityAttrib)) {
        error = GetLastError();
        // Fail to create folder for OPEN_ALWAYS is not an error
        if (error != ERROR_ALREADY_EXISTS ||
            creationDisposition == CREATE_NEW) {
          DbgPrint(L"\terror code = %d\n\n", error);
          status = DokanNtStatusFromWin32(error);
        }
      }

      if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
        // Clean Up operation for impersonate
        DWORD lastError = GetLastError();
        if (status != STATUS_SUCCESS) //Keep the handle open for CreateFile
          CloseHandle(userTokenHandle);
        RevertToSelf();
        SetLastError(lastError);
      }
    }

    if (status == STATUS_SUCCESS) {

      //Check first if we're trying to open a file as a directory.
      if (fileAttr != INVALID_FILE_ATTRIBUTES &&
          !(fileAttr & FILE_ATTRIBUTE_DIRECTORY) &&
          (CreateOptions & FILE_DIRECTORY_FILE)) {
        return STATUS_NOT_A_DIRECTORY;
      }

      if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
        // if g_ImpersonateCallerUser option is on, call the ImpersonateLoggedOnUser function.
        if (!ImpersonateLoggedOnUser(userTokenHandle)) {
          // handle the error if failed to impersonate
          DbgPrint(L"\tImpersonateLoggedOnUser failed.\n");
        }
      }

      // FILE_FLAG_BACKUP_SEMANTICS is required for opening directory handles
      handle =
          CreateFile(filePath, genericDesiredAccess, ShareAccess,
                     &securityAttrib, OPEN_EXISTING,
                     fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS, NULL);

      if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
        // Clean Up operation for impersonate
        DWORD lastError = GetLastError();
        CloseHandle(userTokenHandle);
        RevertToSelf();
        SetLastError(lastError);
      }

      if (handle == INVALID_HANDLE_VALUE) {
        error = GetLastError();
        DbgPrint(L"\terror code = %d\n\n", error);

        status = DokanNtStatusFromWin32(error);
      } else {
        DokanFileInfo->Context =
          (ULONG64)handle; // save the file handle in Context

        // Open succeed but we need to inform the driver
        // that the dir open and not created by returning STATUS_OBJECT_NAME_COLLISION
        if (creationDisposition == OPEN_ALWAYS &&
            fileAttr != INVALID_FILE_ATTRIBUTES)
          return STATUS_OBJECT_NAME_COLLISION;
      }
    }
  } else {
    // It is a create file request

    // Cannot overwrite a hidden or system file if flag not set
    if (fileAttr != INVALID_FILE_ATTRIBUTES &&
        ((!(fileAttributesAndFlags & FILE_ATTRIBUTE_HIDDEN) &&
          (fileAttr & FILE_ATTRIBUTE_HIDDEN)) ||
         (!(fileAttributesAndFlags & FILE_ATTRIBUTE_SYSTEM) &&
          (fileAttr & FILE_ATTRIBUTE_SYSTEM))) &&
        (creationDisposition == TRUNCATE_EXISTING ||
         creationDisposition == CREATE_ALWAYS))
      return STATUS_ACCESS_DENIED;

    // Cannot delete a read only file
    if ((fileAttr != INVALID_FILE_ATTRIBUTES &&
         (fileAttr & FILE_ATTRIBUTE_READONLY) ||
         (fileAttributesAndFlags & FILE_ATTRIBUTE_READONLY)) &&
        (fileAttributesAndFlags & FILE_FLAG_DELETE_ON_CLOSE))
      return STATUS_CANNOT_DELETE;

    // Truncate should always be used with write access
    if (creationDisposition == TRUNCATE_EXISTING)
      genericDesiredAccess |= GENERIC_WRITE;

    if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
      // if g_ImpersonateCallerUser option is on, call the ImpersonateLoggedOnUser function.
      if (!ImpersonateLoggedOnUser(userTokenHandle)) {
        // handle the error if failed to impersonate
        DbgPrint(L"\tImpersonateLoggedOnUser failed.\n");
      }
    }

    handle =
        CreateFile(filePath, genericDesiredAccess, ShareAccess, &securityAttrib,
                   creationDisposition, fileAttributesAndFlags, NULL); 

    if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
      // Clean Up operation for impersonate
      DWORD lastError = GetLastError();
      CloseHandle(userTokenHandle);
      RevertToSelf();
      SetLastError(lastError);
    }

    if (handle == INVALID_HANDLE_VALUE) {
      error = GetLastError();
      DbgPrint(L"\terror code = %d\n\n", error);

      status = DokanNtStatusFromWin32(error);
    } else {

      //Need to update FileAttributes with previous when Overwrite file
      if (fileAttr != INVALID_FILE_ATTRIBUTES &&
          creationDisposition == TRUNCATE_EXISTING) {
        SetFileAttributes(filePath, fileAttributesAndFlags | fileAttr);
      }

      DokanFileInfo->Context =
        (ULONG64)handle; // save the file handle in Context

      if (creationDisposition == OPEN_ALWAYS ||
          creationDisposition == CREATE_ALWAYS) {
        error = GetLastError();
        if (error == ERROR_ALREADY_EXISTS) {
          DbgPrint(L"\tOpen an already existing file\n");
          // Open succeed but we need to inform the driver
          // that the file open and not created by returning STATUS_OBJECT_NAME_COLLISION
          status = STATUS_OBJECT_NAME_COLLISION;
        }
      }
    }
  }

  // 对频繁访问的文件保持句柄
  if (IsFrequentAccess(FileName)) {
    handle = GetCachedHandle(FileName);
    if (handle != INVALID_HANDLE_VALUE) {
      DokanFileInfo->Context = (ULONG64)handle;
      return STATUS_SUCCESS;
    }
  }

  DbgPrint(L"\n");
  return status;
}

#pragma warning(push)
#pragma warning(disable : 4305)

static void DOKAN_CALLBACK MirrorCloseFile(LPCWSTR FileName,
                                           PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  if (DokanFileInfo->Context) {
    DbgPrint(L"CloseFile: %s\n", filePath);
    DbgPrint(L"\terror : not cleanuped file\n\n");
    CloseHandle((HANDLE)DokanFileInfo->Context);
    DokanFileInfo->Context = 0;
  } else {
    DbgPrint(L"Close: %s\n\n", filePath);
  }
}

static void DOKAN_CALLBACK MirrorCleanup(LPCWSTR FileName,
                                         PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  if (DokanFileInfo->Context) {
    DbgPrint(L"Cleanup: %s\n\n", filePath);
    CloseHandle((HANDLE)(DokanFileInfo->Context));
    DokanFileInfo->Context = 0;
  } else {
    DbgPrint(L"Cleanup: %s\n\tinvalid handle\n\n", filePath);
  }

  if (DokanFileInfo->DeleteOnClose) {
    // Should already be deleted by CloseHandle
    // if open with FILE_FLAG_DELETE_ON_CLOSE
    DbgPrint(L"\tDeleteOnClose\n");
    if (DokanFileInfo->IsDirectory) {
      DbgPrint(L"  DeleteDirectory ");
      if (!RemoveDirectory(filePath)) {
        DbgPrint(L"error code = %d\n\n", GetLastError());
      } else {
        DbgPrint(L"success\n\n");
      }
    } else {
      DbgPrint(L"  DeleteFile ");
      if (DeleteFile(filePath) == 0) {
        DbgPrint(L" error code = %d\n\n", GetLastError());
      } else {
        DbgPrint(L"success\n\n");
      }
    }
  }
}

static NTSTATUS DOKAN_CALLBACK MirrorReadFile(LPCWSTR FileName, LPVOID Buffer,
                                              DWORD BufferLength,
                                              LPDWORD ReadLength,
                                              LONGLONG Offset,
                                              PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle = (HANDLE)DokanFileInfo->Context;
  ULONG offset = (ULONG)Offset;
  BOOL opened = FALSE;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"ReadFile : %s\n", filePath);

  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle, cleanuped?\n");
    handle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                        OPEN_EXISTING, 0, NULL);
    if (handle == INVALID_HANDLE_VALUE) {
      DWORD error = GetLastError();
      DbgPrint(L"\tCreateFile error : %d\n\n", error);
      return DokanNtStatusFromWin32(error);
    }
    opened = TRUE;
  }

  // 大文件使用异步IO
  if (BufferLength > 1024*1024) {
    OVERLAPPED overlap = {0};
    overlap.Offset = (DWORD)(Offset & 0xFFFFFFFF);
    overlap.OffsetHigh = (DWORD)(Offset >> 32);
    overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    if (!ReadFileEx(handle, Buffer, BufferLength, &overlap, NULL)) {
      DWORD error = GetLastError();
      if (error != ERROR_IO_PENDING) {
        CloseHandle(overlap.hEvent);
        return DokanNtStatusFromWin32(error);
      }
    }
    
    // 等待IO完成
    WaitForSingleObject(overlap.hEvent, INFINITE);
    CloseHandle(overlap.hEvent);
  }
  // 小文件使用缓存
  else {
    CACHE_ENTRY* entry = FindCacheEntry(Offset);
    if (entry) {
      memcpy(Buffer, entry->data, min(BufferLength, entry->size));
      *ReadLength = min(BufferLength, entry->size);
      return STATUS_SUCCESS;
    }
  }
  
  if (opened)
    CloseHandle(handle);

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorWriteFile(LPCWSTR FileName, LPCVOID Buffer,
                                               DWORD NumberOfBytesToWrite,
                                               LPDWORD NumberOfBytesWritten,
                                               LONGLONG Offset,
                                               PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle = (HANDLE)DokanFileInfo->Context;
  BOOL opened = FALSE;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"WriteFile : %s, offset %I64d, length %d\n", filePath, Offset,
           NumberOfBytesToWrite);

  // 小文件写入缓存合并
  if (NumberOfBytesToWrite < 64*1024) {
    EnterCriticalSection(&g_Cache.lock);
    
    // 添加到写缓存
    if (g_Cache.writeBufferSize + NumberOfBytesToWrite <= WRITE_BUFFER_SIZE) {
      memcpy(g_Cache.writeBuffer + g_Cache.writeBufferSize,
             Buffer, NumberOfBytesToWrite);
      g_Cache.writeBufferSize += NumberOfBytesToWrite;
      *NumberOfBytesWritten = NumberOfBytesToWrite;
      
      // 缓冲区满则刷新
      if (g_Cache.writeBufferSize >= WRITE_BUFFER_SIZE) {
        FlushWriteBuffer();
      }
    }
    
    LeaveCriticalSection(&g_Cache.lock);
    return STATUS_SUCCESS;
  }
  
  // 大文件直接写入
  OVERLAPPED overlap = {0};
  overlap.Offset = (DWORD)(Offset & 0xFFFFFFFF);
  overlap.OffsetHigh = (DWORD)(Offset >> 32);
  
  if (!WriteFile(handle, Buffer, NumberOfBytesToWrite,
                 NumberOfBytesWritten, &overlap)) {
    return DokanNtStatusFromWin32(GetLastError());
  }

  // close the file when it is reopened
  if (opened)
    CloseHandle(handle);

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorFlushFileBuffers(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle = (HANDLE)DokanFileInfo->Context;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"FlushFileBuffers : %s\n", filePath);

  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_SUCCESS;
  }

  if (FlushFileBuffers(handle)) {
    return STATUS_SUCCESS;
  } else {
    DWORD error = GetLastError();
    DbgPrint(L"\tflush error code = %d\n", error);
    return DokanNtStatusFromWin32(error);
  }
}

static NTSTATUS DOKAN_CALLBACK MirrorGetFileInformation(
  LPCWSTR FileName, LPBY_HANDLE_FILE_INFORMATION HandleFileInformation,
  PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle = (HANDLE)DokanFileInfo->Context;
  BOOL opened = FALSE;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"GetFileInfo : %s\n", filePath);

  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle, cleanuped?\n");
    handle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                        OPEN_EXISTING, 0, NULL);
    if (handle == INVALID_HANDLE_VALUE) {
      DWORD error = GetLastError();
      DbgPrint(L"\tCreateFile error : %d\n\n", error);
      return DokanNtStatusFromWin32(error);
    }
    opened = TRUE;
  }

  if (!GetFileInformationByHandle(handle, HandleFileInformation)) {
    DbgPrint(L"\terror code = %d\n", GetLastError());

    // FileName is a root directory
    // in this case, FindFirstFile can't get directory information
    if (wcslen(FileName) == 1) {
      DbgPrint(L"  root dir\n");
      HandleFileInformation->dwFileAttributes = GetFileAttributes(filePath);

    } else {
      WIN32_FIND_DATAW find;
      ZeroMemory(&find, sizeof(WIN32_FIND_DATAW));
      HANDLE findHandle = FindFirstFile(filePath, &find);
      if (findHandle == INVALID_HANDLE_VALUE) {
        DWORD error = GetLastError();
        DbgPrint(L"\tFindFirstFile error code = %d\n\n", error);
        if (opened)
          CloseHandle(handle);
        return DokanNtStatusFromWin32(error);
      }
      HandleFileInformation->dwFileAttributes = find.dwFileAttributes;
      HandleFileInformation->ftCreationTime = find.ftCreationTime;
      HandleFileInformation->ftLastAccessTime = find.ftLastAccessTime;
      HandleFileInformation->ftLastWriteTime = find.ftLastWriteTime;
      HandleFileInformation->nFileSizeHigh = find.nFileSizeHigh;
      HandleFileInformation->nFileSizeLow = find.nFileSizeLow;
      DbgPrint(L"\tFindFiles OK, file size = %d\n", find.nFileSizeLow);
      FindClose(findHandle);
    }
  } else {
    DbgPrint(L"\tGetFileInformationByHandle success, file size = %d\n",
             HandleFileInformation->nFileSizeLow);
  }

  DbgPrint(L"FILE ATTRIBUTE  = %d\n", HandleFileInformation->dwFileAttributes);

  if (opened)
    CloseHandle(handle);

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorFindFiles(LPCWSTR FileName,
                PFillFindData FillFindData, // function pointer
                PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  size_t fileLen;
  HANDLE hFind;
  WIN32_FIND_DATAW findData;
  DWORD error;
  int count = 0;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"FindFiles : %s\n", filePath);

  fileLen = wcslen(filePath);
  if (filePath[fileLen - 1] != L'\\') {
    filePath[fileLen++] = L'\\';
  }
  if (fileLen + 1 >= DOKAN_MAX_PATH)
    return STATUS_BUFFER_OVERFLOW;
  filePath[fileLen] = L'*';
  filePath[fileLen + 1] = L'\0';

  hFind = FindFirstFile(filePath, &findData);

  if (hFind == INVALID_HANDLE_VALUE) {
    error = GetLastError();
    DbgPrint(L"\tinvalid file handle. Error is %u\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  // Root folder does not have . and .. folder - we remove them
  BOOLEAN rootFolder = (wcscmp(FileName, L"\\") == 0);
  do {
    if (!rootFolder || (wcscmp(findData.cFileName, L".") != 0 &&
                        wcscmp(findData.cFileName, L"..") != 0))
      FillFindData(&findData, DokanFileInfo);
    count++;
  } while (FindNextFile(hFind, &findData) != 0);

  error = GetLastError();
  FindClose(hFind);

  if (error != ERROR_NO_MORE_FILES) {
    DbgPrint(L"\tFindNextFile error. Error is %u\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  DbgPrint(L"\tFindFiles return %d entries in %s\n\n", count, filePath);

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorDeleteFile(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle = (HANDLE)DokanFileInfo->Context;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);
  DbgPrint(L"DeleteFile %s - %d\n", filePath, DokanFileInfo->DeleteOnClose);

  DWORD dwAttrib = GetFileAttributes(filePath);

  if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
      (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
    return STATUS_ACCESS_DENIED;

  if (handle && handle != INVALID_HANDLE_VALUE) {
    FILE_DISPOSITION_INFO fdi;
    fdi.DeleteFile = DokanFileInfo->DeleteOnClose;
    if (!SetFileInformationByHandle(handle, FileDispositionInfo, &fdi,
                                    sizeof(FILE_DISPOSITION_INFO)))
      return DokanNtStatusFromWin32(GetLastError());
  }

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorDeleteDirectory(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  // HANDLE	handle = (HANDLE)DokanFileInfo->Context;
  HANDLE hFind;
  WIN32_FIND_DATAW findData;
  size_t fileLen;

  ZeroMemory(filePath, sizeof(filePath));
  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"DeleteDirectory %s - %d\n", filePath,
           DokanFileInfo->DeleteOnClose);

  if (!DokanFileInfo->DeleteOnClose)
    //Dokan notify that the file is requested not to be deleted.
    return STATUS_SUCCESS;

  fileLen = wcslen(filePath);
  if (filePath[fileLen - 1] != L'\\') {
    filePath[fileLen++] = L'\\';
  }
  if (fileLen + 1 >= DOKAN_MAX_PATH)
    return STATUS_BUFFER_OVERFLOW;
  filePath[fileLen] = L'*';
  filePath[fileLen + 1] = L'\0';

  hFind = FindFirstFile(filePath, &findData);

  if (hFind == INVALID_HANDLE_VALUE) {
    DWORD error = GetLastError();
    DbgPrint(L"\tDeleteDirectory error code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  do {
    if (wcscmp(findData.cFileName, L"..") != 0 &&
        wcscmp(findData.cFileName, L".") != 0) {
      FindClose(hFind);
      DbgPrint(L"\tDirectory is not empty: %s\n", findData.cFileName);
      return STATUS_DIRECTORY_NOT_EMPTY;
    }
  } while (FindNextFile(hFind, &findData) != 0);

  DWORD error = GetLastError();

  FindClose(hFind);

  if (error != ERROR_NO_MORE_FILES) {
    DbgPrint(L"\tDeleteDirectory error code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorMoveFile(LPCWSTR FileName, // existing file name
               LPCWSTR NewFileName, BOOL ReplaceIfExisting,
               PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  WCHAR newFilePath[DOKAN_MAX_PATH];
  HANDLE handle;
  DWORD bufferSize;
  BOOL result;
  size_t newFilePathLen;

  PFILE_RENAME_INFO renameInfo = NULL;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);
  if (wcslen(NewFileName) && NewFileName[0] != ':') {
    GetFilePath(newFilePath, DOKAN_MAX_PATH, NewFileName);
  } else {
    // For a stream rename, FileRenameInfo expect the FileName param without the filename
    // like :<stream name>:<stream type>
    wcsncpy_s(newFilePath, DOKAN_MAX_PATH, NewFileName, wcslen(NewFileName));
  }

  DbgPrint(L"MoveFile %s -> %s\n\n", filePath, newFilePath);
  handle = (HANDLE)DokanFileInfo->Context;
  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  newFilePathLen = wcslen(newFilePath);

  // the PFILE_RENAME_INFO struct has space for one WCHAR for the name at
  // the end, so that
  // accounts for the null terminator

  bufferSize = (DWORD)(sizeof(FILE_RENAME_INFO) +
                       newFilePathLen * sizeof(newFilePath[0]));

  renameInfo = (PFILE_RENAME_INFO)malloc(bufferSize);
  if (!renameInfo) {
    return STATUS_BUFFER_OVERFLOW;
  }
  ZeroMemory(renameInfo, bufferSize);

  renameInfo->ReplaceIfExists =
    ReplaceIfExisting
      ? TRUE
          : FALSE; // some warning about converting BOOL to BOOLEAN
  renameInfo->RootDirectory = NULL; // hope it is never needed, shouldn't be
  renameInfo->FileNameLength =
    (DWORD)newFilePathLen *
    sizeof(newFilePath[0]); // they want length in bytes

  wcscpy_s(renameInfo->FileName, newFilePathLen + 1, newFilePath);

  result = SetFileInformationByHandle(handle, FileRenameInfo, renameInfo,
                                      bufferSize);

  free(renameInfo);

  if (result) {
    return STATUS_SUCCESS;
  } else {
    DWORD error = GetLastError();
    DbgPrint(L"\tMoveFile error = %u\n", error);
    return DokanNtStatusFromWin32(error);
  }
}

static NTSTATUS DOKAN_CALLBACK MirrorLockFile(LPCWSTR FileName,
                                              LONGLONG ByteOffset,
                                              LONGLONG Length,
                                              PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle;
  LARGE_INTEGER offset;
  LARGE_INTEGER length;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"LockFile %s\n", filePath);

  handle = (HANDLE)DokanFileInfo->Context;
  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  length.QuadPart = Length;
  offset.QuadPart = ByteOffset;

  if (!LockFile(handle, offset.LowPart, offset.HighPart, length.LowPart,
                length.HighPart)) {
    DWORD error = GetLastError();
    DbgPrint(L"\terror code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  DbgPrint(L"\tsuccess\n\n");
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorSetEndOfFile(
  LPCWSTR FileName, LONGLONG ByteOffset, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle;
  LARGE_INTEGER offset;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"SetEndOfFile %s, %I64d\n", filePath, ByteOffset);

  handle = (HANDLE)DokanFileInfo->Context;
  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  offset.QuadPart = ByteOffset;
  if (!SetFilePointerEx(handle, offset, NULL, FILE_BEGIN)) {
    DWORD error = GetLastError();
    DbgPrint(L"\tSetFilePointer error: %d, offset = %I64d\n\n", error,
             ByteOffset);
    return DokanNtStatusFromWin32(error);
  }

  if (!SetEndOfFile(handle)) {
    DWORD error = GetLastError();
    DbgPrint(L"\tSetEndOfFile error code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorSetAllocationSize(
  LPCWSTR FileName, LONGLONG AllocSize, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle;
  LARGE_INTEGER fileSize;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"SetAllocationSize %s, %I64d\n", filePath, AllocSize);

  handle = (HANDLE)DokanFileInfo->Context;
  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  if (GetFileSizeEx(handle, &fileSize)) {
    if (AllocSize < fileSize.QuadPart) {
      fileSize.QuadPart = AllocSize;
      if (!SetFilePointerEx(handle, fileSize, NULL, FILE_BEGIN)) {
        DWORD error = GetLastError();
        DbgPrint(L"\tSetAllocationSize: SetFilePointer eror: %d, "
                 L"offset = %I64d\n\n",
                 error, AllocSize);
        return DokanNtStatusFromWin32(error);
      }
      if (!SetEndOfFile(handle)) {
        DWORD error = GetLastError();
        DbgPrint(L"\tSetEndOfFile error code = %d\n\n", error);
        return DokanNtStatusFromWin32(error);
      }
    }
  } else {
    DWORD error = GetLastError();
    DbgPrint(L"\terror code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorSetFileAttributes(
  LPCWSTR FileName, DWORD FileAttributes, PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);

  WCHAR filePath[DOKAN_MAX_PATH];

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"SetFileAttributes %s 0x%x\n", filePath, FileAttributes);

  if (FileAttributes != 0) {
    if (!SetFileAttributes(filePath, FileAttributes)) {
      DWORD error = GetLastError();
      DbgPrint(L"\terror code = %d\n\n", error);
      return DokanNtStatusFromWin32(error);
    }
  } else {
    // case FileAttributes == 0 :
    // MS-FSCC 2.6 File Attributes : There is no file attribute with the value 0x00000000
    // because a value of 0x00000000 in the FileAttributes field means that the file attributes for this file MUST NOT be changed when setting basic information for the file
    DbgPrint(L"Set 0 to FileAttributes means MUST NOT be changed. Didn't call "
             L"SetFileAttributes function. \n");
  }

  DbgPrint(L"\n");
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorSetFileTime(LPCWSTR FileName, CONST FILETIME *CreationTime,
                  CONST FILETIME *LastAccessTime, CONST FILETIME *LastWriteTime,
                  PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"SetFileTime %s\n", filePath);

  handle = (HANDLE)DokanFileInfo->Context;

  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  if (!SetFileTime(handle, CreationTime, LastAccessTime, LastWriteTime)) {
    DWORD error = GetLastError();
    DbgPrint(L"\terror code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  DbgPrint(L"\n");
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK
MirrorUnlockFile(LPCWSTR FileName, LONGLONG ByteOffset, LONGLONG Length,
                 PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE handle;
  LARGE_INTEGER length;
  LARGE_INTEGER offset;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"UnlockFile %s\n", filePath);

  handle = (HANDLE)DokanFileInfo->Context;
  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  length.QuadPart = Length;
  offset.QuadPart = ByteOffset;

  if (!UnlockFile(handle, offset.LowPart, offset.HighPart, length.LowPart,
                  length.HighPart)) {
    DWORD error = GetLastError();
    DbgPrint(L"\terror code = %d\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  DbgPrint(L"\tsuccess\n\n");
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorGetFileSecurity(
  LPCWSTR FileName, PSECURITY_INFORMATION SecurityInformation,
  PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG BufferLength,
  PULONG LengthNeeded, PDOKAN_FILE_INFO DokanFileInfo) {
  WCHAR filePath[DOKAN_MAX_PATH];
  BOOLEAN requestingSaclInfo;

  UNREFERENCED_PARAMETER(DokanFileInfo);

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"GetFileSecurity %s\n", filePath);

  MirrorCheckFlag(*SecurityInformation, FILE_SHARE_READ);
  MirrorCheckFlag(*SecurityInformation, OWNER_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, GROUP_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, DACL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, SACL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, LABEL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, ATTRIBUTE_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, SCOPE_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation,
    PROCESS_TRUST_LABEL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, BACKUP_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, PROTECTED_DACL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, PROTECTED_SACL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, UNPROTECTED_DACL_SECURITY_INFORMATION);
  MirrorCheckFlag(*SecurityInformation, UNPROTECTED_SACL_SECURITY_INFORMATION);

  requestingSaclInfo = ((*SecurityInformation & SACL_SECURITY_INFORMATION) ||
                        (*SecurityInformation & BACKUP_SECURITY_INFORMATION));

  if (!g_HasSeSecurityPrivilege) {
    *SecurityInformation &= ~SACL_SECURITY_INFORMATION;
    *SecurityInformation &= ~BACKUP_SECURITY_INFORMATION;
  }

  DbgPrint(L"  Opening new handle with READ_CONTROL access\n");
  HANDLE handle = CreateFile(
      filePath,
      READ_CONTROL | ((requestingSaclInfo && g_HasSeSecurityPrivilege)
                          ? ACCESS_SYSTEM_SECURITY
                          : 0),
      FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
      NULL, // security attribute
      OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS, // |FILE_FLAG_NO_BUFFERING,
      NULL);

  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    int error = GetLastError();
    return DokanNtStatusFromWin32(error);
  }

  if (!GetUserObjectSecurity(handle, SecurityInformation, SecurityDescriptor,
                             BufferLength, LengthNeeded)) {
    int error = GetLastError();
    if (error == ERROR_INSUFFICIENT_BUFFER) {
      DbgPrint(L"  GetUserObjectSecurity error: ERROR_INSUFFICIENT_BUFFER\n");
      CloseHandle(handle);
      return STATUS_BUFFER_OVERFLOW;
    } else {
      DbgPrint(L"  GetUserObjectSecurity error: %d\n", error);
      CloseHandle(handle);
      return DokanNtStatusFromWin32(error);
    }
  }

  // Ensure the Security Descriptor Length is set
  DWORD securityDescriptorLength =
    GetSecurityDescriptorLength(SecurityDescriptor);
  DbgPrint(L"  GetUserObjectSecurity return true,  *LengthNeeded = "
           L"securityDescriptorLength \n");
  *LengthNeeded = securityDescriptorLength;

  CloseHandle(handle);

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorSetFileSecurity(
  LPCWSTR FileName, PSECURITY_INFORMATION SecurityInformation,
  PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG SecurityDescriptorLength,
  PDOKAN_FILE_INFO DokanFileInfo) {
  HANDLE handle;
  WCHAR filePath[DOKAN_MAX_PATH];

  UNREFERENCED_PARAMETER(SecurityDescriptorLength);

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"SetFileSecurity %s\n", filePath);

  handle = (HANDLE)DokanFileInfo->Context;
  if (!handle || handle == INVALID_HANDLE_VALUE) {
    DbgPrint(L"\tinvalid handle\n\n");
    return STATUS_INVALID_HANDLE;
  }

  if (!SetUserObjectSecurity(handle, SecurityInformation, SecurityDescriptor)) {
    int error = GetLastError();
    DbgPrint(L"  SetUserObjectSecurity error: %d\n", error);
    return DokanNtStatusFromWin32(error);
  }
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorGetVolumeInformation(
  LPWSTR VolumeNameBuffer, DWORD VolumeNameSize, LPDWORD VolumeSerialNumber,
  LPDWORD MaximumComponentLength, LPDWORD FileSystemFlags,
  LPWSTR FileSystemNameBuffer, DWORD FileSystemNameSize,
  PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);

  WCHAR volumeRoot[4];
  DWORD fsFlags = 0;

  wcscpy_s(VolumeNameBuffer, VolumeNameSize, gVolumeName);

  if (VolumeSerialNumber)
    *VolumeSerialNumber = 0x19831116;
  if (MaximumComponentLength)
    *MaximumComponentLength = 255;
  if (FileSystemFlags) {
    *FileSystemFlags = FILE_SUPPORTS_REMOTE_STORAGE | FILE_UNICODE_ON_DISK |
                       FILE_PERSISTENT_ACLS | FILE_NAMED_STREAMS;
    if (g_CaseSensitive)
      *FileSystemFlags = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
  }

  volumeRoot[0] = gRootDirectory[0];
  volumeRoot[1] = ':';
  volumeRoot[2] = '\\';
  volumeRoot[3] = '\0';

  if (GetVolumeInformation(volumeRoot, NULL, 0, NULL, MaximumComponentLength,
                           &fsFlags, FileSystemNameBuffer,
                           FileSystemNameSize)) {

    if (FileSystemFlags)
      *FileSystemFlags &= fsFlags;

    if (MaximumComponentLength) {
      DbgPrint(L"GetVolumeInformation: max component length %u\n",
               *MaximumComponentLength);
    }
    if (FileSystemNameBuffer) {
      DbgPrint(L"GetVolumeInformation: file system name %s\n",
               FileSystemNameBuffer);
    }
    if (FileSystemFlags) {
      DbgPrint(L"GetVolumeInformation: got file system flags 0x%08x,"
               L" returning 0x%08x\n",
               fsFlags, *FileSystemFlags);
    }
  } else {

    DbgPrint(L"GetVolumeInformation: unable to query underlying fs,"
             L" using defaults.  Last error = %u\n",
             GetLastError());

    // File system name could be anything up to 10 characters.
    // But Windows check few feature availability based on file system name.
    // For this, it is recommended to set NTFS or FAT here.
    wcscpy_s(FileSystemNameBuffer, FileSystemNameSize, L"NTFS");
  }

  return STATUS_SUCCESS;
}

// Uncomment the function and set dokanOperations.GetDiskFreeSpace to personalize disk space
/*
static NTSTATUS DOKAN_CALLBACK MirrorDokanGetDiskFreeSpace(
    PULONGLONG FreeBytesAvailable, PULONGLONG TotalNumberOfBytes,
    PULONGLONG TotalNumberOfFreeBytes, PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);

  *FreeBytesAvailable = (ULONGLONG)(512 * 1024 * 1024);
  *TotalNumberOfBytes = 9223372036854775807;
  *TotalNumberOfFreeBytes = 9223372036854775807;

  return STATUS_SUCCESS;
}
*/

static NTSTATUS DOKAN_CALLBACK MirrorDokanGetDiskFreeSpace(
    PULONGLONG FreeBytesAvailable, PULONGLONG TotalNumberOfBytes,
    PULONGLONG TotalNumberOfFreeBytes, PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);
  WCHAR DriveLetter[3] = {'C', ':', 0};
  PWCHAR RootPathName;

  if (gRootDirectory[0] == L'\\') { // UNC as Root
    RootPathName = gRootDirectory;
  } else {
    DriveLetter[0] = gRootDirectory[0];
    RootPathName = DriveLetter;
  }

  if (!GetDiskFreeSpaceExW(RootPathName, (PULARGE_INTEGER)FreeBytesAvailable,
                           (PULARGE_INTEGER)TotalNumberOfBytes,
                           (PULARGE_INTEGER)TotalNumberOfFreeBytes)) {
    DWORD error = GetLastError();
    DbgPrint(L"GetDiskFreeSpaceEx failed for path %ws", RootPathName);
    return DokanNtStatusFromWin32(error);
  }
  return STATUS_SUCCESS;
}

/**
 * Avoid #include <winternl.h> which as conflict with FILE_INFORMATION_CLASS
 * definition.
 * This only for MirrorFindStreams. Link with ntdll.lib still required.
 *
 * Not needed if you're not using NtQueryInformationFile!
 *
 * BEGIN
 */
#pragma warning(push)
#pragma warning(disable : 4201)
typedef struct _IO_STATUS_BLOCK {
  union {
    NTSTATUS Status;
    PVOID Pointer;
  } DUMMYUNIONNAME;

  ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
#pragma warning(pop)

NTSYSCALLAPI NTSTATUS NTAPI NtQueryInformationFile(
    _In_ HANDLE FileHandle, _Out_ PIO_STATUS_BLOCK IoStatusBlock,
    _Out_writes_bytes_(Length) PVOID FileInformation, _In_ ULONG Length,
    _In_ FILE_INFORMATION_CLASS FileInformationClass);
/**
 * END
 */

NTSTATUS DOKAN_CALLBACK
MirrorFindStreams(LPCWSTR FileName, PFillFindStreamData FillFindStreamData,
                  PVOID FindStreamContext,
                  PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);

  WCHAR filePath[DOKAN_MAX_PATH];
  HANDLE hFind;
  WIN32_FIND_STREAM_DATA findData;
  DWORD error;
  int count = 0;

  GetFilePath(filePath, DOKAN_MAX_PATH, FileName);

  DbgPrint(L"FindStreams :%s\n", filePath);

  hFind = FindFirstStreamW(filePath, FindStreamInfoStandard, &findData, 0);

  if (hFind == INVALID_HANDLE_VALUE) {
    error = GetLastError();
    DbgPrint(L"\tinvalid file handle. Error is %u\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  BOOL bufferFull = FillFindStreamData(&findData, FindStreamContext);
  if (bufferFull) {
    count++;
    while (FindNextStreamW(hFind, &findData) != 0) {
      bufferFull = FillFindStreamData(&findData, FindStreamContext);
      if (!bufferFull)
        break;
      count++;
    }
  }

  error = GetLastError();
  FindClose(hFind);

  if (!bufferFull) {
    DbgPrint(L"\tFindStreams returned %d entries in %s with "
             L"STATUS_BUFFER_OVERFLOW\n\n",
             count, filePath);
    // https://msdn.microsoft.com/en-us/library/windows/hardware/ff540364(v=vs.85).aspx
    return STATUS_BUFFER_OVERFLOW;
  }

  if (error != ERROR_HANDLE_EOF) {
    DbgPrint(L"\tFindNextStreamW error. Error is %u\n\n", error);
    return DokanNtStatusFromWin32(error);
  }

  DbgPrint(L"\tFindStreams return %d entries in %s\n\n", count, filePath);

  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorMounted(LPCWSTR MountPoint,
                                             PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);

  DbgPrint(L"Mounted as %s\n", MountPoint);
  return STATUS_SUCCESS;
}

static NTSTATUS DOKAN_CALLBACK MirrorUnmounted(PDOKAN_FILE_INFO DokanFileInfo) {
  UNREFERENCED_PARAMETER(DokanFileInfo);

  DbgPrint(L"Unmounted\n");
  return STATUS_SUCCESS;
}

#pragma warning(pop)

BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
  switch (dwCtrlType) {
  case CTRL_C_EVENT:
  case CTRL_BREAK_EVENT:
  case CTRL_CLOSE_EVENT:
  case CTRL_LOGOFF_EVENT:
  case CTRL_SHUTDOWN_EVENT:
    SetConsoleCtrlHandler(CtrlHandler, FALSE);
    DokanRemoveMountPoint(gMountPoint);
    return TRUE;
  default:
    return FALSE;
  }
}

void ShowUsage() {
  // clang-format off
  fprintf(stderr, "mirror.exe - Mirror a local device or folder to secondary device, an NTFS folder or a network device.\n"
          "  /r RootDirectory (ex. /r c:\\test)\t\t Directory source to mirror.\n"
          "  /l MountPoint (ex. /l m)\t\t\t Mount point. Can be M:\\ (drive letter) or empty NTFS folder C:\\mount\\dokan .\n"
          "  /t Single thread\t\t\t\t Only use a single thread to process events.\n\t\t\t\t\t\t This is highly not recommended as can easily create a bottleneck.\n"
          "  /g IPC Batching\t\t\t\t Pull batches of events from the driver instead of a single one and execute them parallelly.\n\t\t\t\t\t\t Only recommended for slow (remote) mirrored device.\n"
          "  /d (enable debug output)\t\t\t Enable debug output to an attached debugger.\n"
          "  /s (use stderr for output)\t\t\t Enable debug output to stderr.\n"
          "  /m (use removable drive)\t\t\t Show device as removable media.\n"
          "  /w (write-protect drive)\t\t\t Read only filesystem.\n"
          "  /b (case sensitive drive)\t\t\t Supports case-sensitive file names.\n"
          "  /o (use mount manager)\t\t\t Register device to Windows mount manager.\n\t\t\t\t\t\t This enables advanced Windows features like recycle bin and more...\n"
          "  /c (mount for current session only)\t\t Device only visible for current user session.\n"
          "  /n (Network drive with UNC name ex. \\myfs\\fs1) Show device as network device with a UNC name.\n"
          "  /p (Impersonate Caller User)\t\t\t Impersonate Caller User when getting the handle in CreateFile for operations.\n\t\t\t\t\t\t This option requires administrator right to work properly.\n"
          "  /a Allocation unit size (ex. /a 512)\t\t Allocation Unit Size of the volume. This will behave on the disk file size.\n"
          "  /k Sector size (ex. /k 512)\t\t\t Sector Size of the volume. This will behave on the disk file size.\n"
          "  /f User mode Lock\t\t\t\t Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it.\n"
          "  /i Timeout in Milliseconds (ex. /i 30000)\t Timeout until a running operation is aborted and the device is unmounted.\n"
          "  /x Network unmount\t\t\t\t Allows unmounting network drive from file explorer.\n"
          "  /e Enable Driver Logs\t\t\t\t Forward Driver logs to userland.\n"
          "  /v Volume name\t\t\t\t Personalize the volume name.\n\n"
          "Examples:\n"
          "\tmirror.exe /r C:\\Users /l M:\t\t\t# Mirror C:\\Users as RootDirectory into a drive of letter M:\\.\n"
          "\tmirror.exe /r C:\\Users /l C:\\mount\\dokan\t# Mirror C:\\Users as RootDirectory into NTFS folder C:\\mount\\dokan.\n"
          "\tmirror.exe /r C:\\Users /l M: /n /u \\myfs\\myfs1\t# Mirror C:\\Users as RootDirectory into a network drive M:\\. with UNC \\\\myfs\\myfs1\n\n"
          "Unmount the drive with CTRL + C in the console or alternatively via \"dokanctl /u MountPoint\".\n");
  // clang-format on
}

#define CHECK_CMD_ARG(commad, argc)                                            \
  {                                                                            \
    if (++command == argc) {                                                   \
      fwprintf(stderr, L"Option is missing an argument.\n");                   \
      return EXIT_FAILURE;                                                     \
    }                                                                          \
  }

int __cdecl wmain(ULONG argc, PWCHAR argv[]) {
  int status;
  ULONG command;
  DOKAN_OPERATIONS dokanOperations;
  DOKAN_OPTIONS dokanOptions;

  if (argc < 3) {
    ShowUsage();
    return EXIT_FAILURE;
  }

  g_DebugMode = FALSE;
  g_UseStdErr = FALSE;
  g_CaseSensitive = FALSE;

  ZeroMemory(&dokanOptions, sizeof(DOKAN_OPTIONS));
  dokanOptions.Version = DOKAN_VERSION;

  // 设置更大的缓冲区
  dokanOptions.AllocationUnitSize = 64 * 1024;  // 64KB
  dokanOptions.SectorSize = 4096;  // 4KB

  // 启用异步IO
  dokanOptions.Options |= DOKAN_OPTION_ALLOW_IPC_BATCHING;

  for (command = 1; command < argc; command++) {
    switch (towlower(argv[command][1])) {
    case L'r':
      CHECK_CMD_ARG(command, argc)
      wcscpy_s(gRootDirectory, sizeof(gRootDirectory) / sizeof(WCHAR),
               argv[command]);
      if (!wcslen(gRootDirectory)) {
        DbgPrint(L"Invalid RootDirectory\n");
        return EXIT_FAILURE;
      }

      DbgPrint(L"RootDirectory: %ls\n", gRootDirectory);
      break;
    case L'l':
      CHECK_CMD_ARG(command, argc)
      wcscpy_s(gMountPoint, sizeof(gMountPoint) / sizeof(WCHAR), argv[command]);
      dokanOptions.MountPoint = gMountPoint;
      break;
     case L't':
      dokanOptions.SingleThread = TRUE;
      break;
    case L'd':
      g_DebugMode = TRUE;
      break;
    case L's':
      g_UseStdErr = TRUE;
      break;
    case L'm':
      dokanOptions.Options |= DOKAN_OPTION_REMOVABLE;
      break;
    case L'w':
      dokanOptions.Options |= DOKAN_OPTION_WRITE_PROTECT;
      break;
    case L'o':
      dokanOptions.Options |= DOKAN_OPTION_MOUNT_MANAGER;
      break;
    case L'c':
      dokanOptions.Options |= DOKAN_OPTION_CURRENT_SESSION;
      break;
    case L'f':
      dokanOptions.Options |= DOKAN_OPTION_FILELOCK_USER_MODE;
      break;
    case L'x':
      dokanOptions.Options |= DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE;
      break;
    case L'e':
      dokanOptions.Options |= DOKAN_OPTION_DISPATCH_DRIVER_LOGS;
      break;
    case L'g':
      dokanOptions.Options |= DOKAN_OPTION_ALLOW_IPC_BATCHING;
      break;
    case L'b':
      // Only work when mirroring a folder with setCaseSensitiveInfo option enabled on win10
      dokanOptions.Options |= DOKAN_OPTION_CASE_SENSITIVE;
      g_CaseSensitive = TRUE;
      break;
    case L'n':
      CHECK_CMD_ARG(command, argc)
      dokanOptions.Options |= DOKAN_OPTION_NETWORK;
      wcscpy_s(gUNCName, sizeof(gUNCName) / sizeof(WCHAR), argv[command]);
      dokanOptions.UNCName = gUNCName;
      DbgPrint(L"UNC Name: %ls\n", gUNCName);
      break;
    case L'v':
      CHECK_CMD_ARG(command, argc)
      wcscpy_s(gVolumeName, sizeof(gVolumeName) / sizeof(WCHAR), argv[command]);
      DbgPrint(L"Volume Name: %ls\n", gVolumeName);
      break;
    case L'p':
      g_ImpersonateCallerUser = TRUE;
      break;
    case L'i':
      CHECK_CMD_ARG(command, argc)
      dokanOptions.Timeout = (ULONG)_wtol(argv[command]);
      break;
    case L'a':
      CHECK_CMD_ARG(command, argc)
      dokanOptions.AllocationUnitSize = (ULONG)_wtol(argv[command]);
      break;
    case L'k':
      CHECK_CMD_ARG(command, argc)
      dokanOptions.SectorSize = (ULONG)_wtol(argv[command]);
      break;
    default:
      fwprintf(stderr, L"unknown command: %ls\n", argv[command]);
      return EXIT_FAILURE;
    }
  }

  if (wcscmp(gUNCName, L"") != 0 &&
      !(dokanOptions.Options & DOKAN_OPTION_NETWORK)) {
    fwprintf(
             stderr,
             L"  Warning: UNC provider name should be set on network drive only.\n");
  }

  if (dokanOptions.Options & DOKAN_OPTION_NETWORK &&
      dokanOptions.Options & DOKAN_OPTION_MOUNT_MANAGER) {
    fwprintf(stderr, L"Mount manager cannot be used on network drive.\n");
    return EXIT_FAILURE;
  }

  if (!(dokanOptions.Options & DOKAN_OPTION_MOUNT_MANAGER) &&
      wcscmp(gMountPoint, L"") == 0) {
    fwprintf(stderr, L"Mount Point required.\n");
    return EXIT_FAILURE;
  }

  if ((dokanOptions.Options & DOKAN_OPTION_MOUNT_MANAGER) &&
      (dokanOptions.Options & DOKAN_OPTION_CURRENT_SESSION)) {
    fwprintf(
             stderr,
             L"Mount Manager always mount the drive for all user sessions.\n");
    return EXIT_FAILURE;
  }

  if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
    fwprintf(stderr, L"Control Handler is not set.\n");
  }

  // Add security name privilege. Required here to handle GetFileSecurity
  // properly.
  g_HasSeSecurityPrivilege = AddSeSecurityNamePrivilege();
  if (!g_HasSeSecurityPrivilege) {
    fwprintf(stderr,
             L"[Mirror] Failed to add security privilege to process\n"
             L"\t=> GetFileSecurity/SetFileSecurity may not work properly\n"
             L"\t=> Please restart mirror sample with administrator rights to fix it\n");
  }

  if (g_ImpersonateCallerUser && !g_HasSeSecurityPrivilege) {
    fwprintf(
        stderr,
        L"[Mirror] Impersonate Caller User requires administrator right to work properly\n"
        L"\t=> Other users may not use the drive properly\n"
        L"\t=> Please restart mirror sample with administrator rights to fix it\n");
  }

  if (g_DebugMode) {
    dokanOptions.Options |= DOKAN_OPTION_DEBUG;
  }
  if (g_UseStdErr) {
    dokanOptions.Options |= DOKAN_OPTION_STDERR;
  }

  dokanOptions.Options |= DOKAN_OPTION_ALT_STREAM;

  // 初始化缓存
  InitializeCache();

  ZeroMemory(&dokanOperations, sizeof(DOKAN_OPERATIONS));
  dokanOperations.ZwCreateFile = MirrorCreateFile;
  dokanOperations.Cleanup = MirrorCleanup;
  dokanOperations.CloseFile = MirrorCloseFile;
  dokanOperations.ReadFile = MirrorReadFile;
  dokanOperations.WriteFile = MirrorWriteFile;
  dokanOperations.FlushFileBuffers = MirrorFlushFileBuffers;
  dokanOperations.GetFileInformation = MirrorGetFileInformation;
  dokanOperations.FindFiles = MirrorFindFiles;
  dokanOperations.FindFilesWithPattern = NULL;
  dokanOperations.SetFileAttributes = MirrorSetFileAttributes;
  dokanOperations.SetFileTime = MirrorSetFileTime;
  dokanOperations.DeleteFile = MirrorDeleteFile;
  dokanOperations.DeleteDirectory = MirrorDeleteDirectory;
  dokanOperations.MoveFile = MirrorMoveFile;
  dokanOperations.SetEndOfFile = MirrorSetEndOfFile;
  dokanOperations.SetAllocationSize = MirrorSetAllocationSize;
  dokanOperations.LockFile = MirrorLockFile;
  dokanOperations.UnlockFile = MirrorUnlockFile;
  dokanOperations.GetFileSecurity = MirrorGetFileSecurity;
  dokanOperations.SetFileSecurity = MirrorSetFileSecurity;
  dokanOperations.GetDiskFreeSpace = MirrorDokanGetDiskFreeSpace;
  dokanOperations.GetVolumeInformation = MirrorGetVolumeInformation;
  dokanOperations.Unmounted = MirrorUnmounted;
  dokanOperations.FindStreams = MirrorFindStreams;
  dokanOperations.Mounted = MirrorMounted;

  DokanInit();
  status = DokanMain(&dokanOptions, &dokanOperations);
  DokanShutdown();
  switch (status) {
  case DOKAN_SUCCESS:
    fprintf(stderr, "Success\n");
    break;
  case DOKAN_ERROR:
    fprintf(stderr, "Error\n");
    break;
  case DOKAN_DRIVE_LETTER_ERROR:
    fprintf(stderr, "Bad Drive letter\n");
    break;
  case DOKAN_DRIVER_INSTALL_ERROR:
    fprintf(stderr, "Can't install driver\n");
    break;
  case DOKAN_START_ERROR:
    fprintf(stderr, "Driver something wrong\n");
    break;
  case DOKAN_MOUNT_ERROR:
    fprintf(stderr, "Can't assign a drive letter\n");
    break;
  case DOKAN_MOUNT_POINT_ERROR:
    fprintf(stderr, "Mount point error\n");
    break;
  case DOKAN_VERSION_ERROR:
    fprintf(stderr, "Version error\n");
    break;
  default:
    fprintf(stderr, "Unknown error: %d\n", status);
    break;
  }
  return EXIT_SUCCESS;
}

// 添加缓存管理相关结构和函数
#define CACHE_SIZE (64*1024*1024)  // 64MB缓存
#define WRITE_BUFFER_SIZE (1024*1024)  // 1MB写缓冲

typedef struct _CACHE_ENTRY {
    BYTE* data;
    LONGLONG offset;
    DWORD size;
    BOOL dirty;
    FILETIME lastAccess;
} CACHE_ENTRY;

typedef struct _CACHE_MANAGER {
    CRITICAL_SECTION lock;
    HANDLE flushThread;
    BOOL shutdownFlag;
    
    // LRU缓存
    CACHE_ENTRY* entries;
    DWORD entryCount;
    
    // 写缓冲
    BYTE* writeBuffer;
    DWORD writeBufferSize;
    LONGLONG writeOffset;
} CACHE_MANAGER;

static CACHE_MANAGER g_Cache;

// 初始化缓存管理器
void InitializeCache() {
    InitializeCriticalSection(&g_Cache.lock);
    
    // 初始化LRU缓存
    g_Cache.entries = (CACHE_ENTRY*)malloc(sizeof(CACHE_ENTRY) * 16);
    g_Cache.entryCount = 0;
    
    // 初始化写缓冲
    g_Cache.writeBuffer = (BYTE*)malloc(WRITE_BUFFER_SIZE);
    g_Cache.writeBufferSize = 0;
    g_Cache.writeOffset = 0;
    
    // 创建刷新线程
    g_Cache.shutdownFlag = FALSE;
    g_Cache.flushThread = CreateThread(NULL, 0, CacheFlushThread, NULL, 0, NULL);
}

// 缓存刷新线程
DWORD WINAPI CacheFlushThread(LPVOID param) {
    while (!g_Cache.shutdownFlag) {
        EnterCriticalSection(&g_Cache.lock);
        
        // 刷新脏页
        for (DWORD i = 0; i < g_Cache.entryCount; i++) {
            if (g_Cache.entries[i].dirty) {
                FlushCacheEntry(&g_Cache.entries[i]);
            }
        }
        
        LeaveCriticalSection(&g_Cache.lock);
        Sleep(1000); // 每秒刷新一次
    }
    return 0;
}

// 添加日志记录
typedef struct _LOG_ENTRY {
    LONGLONG offset;
    DWORD length;
    BYTE* data;
} LOG_ENTRY;

static void LogWrite(LONGLONG offset, LPCVOID data, DWORD length) {
    // 写入日志
    LOG_ENTRY entry;
    entry.offset = offset;
    entry.length = length;
    entry.data = malloc(length);
    memcpy(entry.data, data, length);
    
    // 持久化日志
    FlushLogEntry(&entry);
}

// 崩溃恢复
static void RecoverFromCrash() {
    // 读取日志
    LOG_ENTRY* entries = ReadLogEntries();
    
    // 重放未完成的写操作
    for (int i = 0; i < logEntryCount; i++) {
        ReplayLogEntry(&entries[i]);
    }
}

// 添加性能计数器
typedef struct _PERFORMANCE_COUNTER {
    LARGE_INTEGER readBytes;
    LARGE_INTEGER writeBytes; 
    LARGE_INTEGER readCount;
    LARGE_INTEGER writeCount;
    
    LARGE_INTEGER lastUpdateTime;
    LARGE_INTEGER frequency;
} PERFORMANCE_COUNTER;

static PERFORMANCE_COUNTER g_PerfCounter;

// 更新性能计数
void UpdatePerformanceCounter(DWORD operation, DWORD bytes) {
    LARGE_INTEGER currentTime;
    QueryPerformanceCounter(&currentTime);
    
    if (operation == READ_OPERATION) {
        InterlockedAdd64(&g_PerfCounter.readBytes.QuadPart, bytes);
        InterlockedIncrement64(&g_PerfCounter.readCount.QuadPart);
    } else {
        InterlockedAdd64(&g_PerfCounter.writeBytes.QuadPart, bytes);
        InterlockedIncrement64(&g_PerfCounter.writeCount.QuadPart);
    }
    
    // 每秒输出性能统计
    if (currentTime.QuadPart - g_PerfCounter.lastUpdateTime.QuadPart > 
        g_PerfCounter.frequency.QuadPart) {
        OutputPerformanceStats();
        g_PerfCounter.lastUpdateTime = currentTime;
    }
}

// 内存池管理
#define MEMORY_POOL_SIZE (256*1024*1024)  // 256MB内存池
#define BLOCK_SIZE (4*1024)  // 4KB块大小

typedef struct _MEMORY_BLOCK {
    BYTE* data;
    struct _MEMORY_BLOCK* next;
    BOOL inUse;
} MEMORY_BLOCK;

typedef struct _MEMORY_POOL {
    CRITICAL_SECTION lock;
    MEMORY_BLOCK* blocks;
    DWORD totalBlocks;
    DWORD freeBlocks;
} MEMORY_POOL;

static MEMORY_POOL g_MemPool;

// 初始化内存池
void InitializeMemoryPool() {
    InitializeCriticalSection(&g_MemPool.lock);
    g_MemPool.totalBlocks = MEMORY_POOL_SIZE / BLOCK_SIZE;
    g_MemPool.blocks = malloc(sizeof(MEMORY_BLOCK) * g_MemPool.totalBlocks);
    g_MemPool.freeBlocks = g_MemPool.totalBlocks;
    
    // 预分配内存块
    BYTE* poolMemory = malloc(MEMORY_POOL_SIZE);
    for (DWORD i = 0; i < g_MemPool.totalBlocks; i++) {
        g_MemPool.blocks[i].data = poolMemory + (i * BLOCK_SIZE);
        g_MemPool.blocks[i].inUse = FALSE;
        g_MemPool.blocks[i].next = (i < g_MemPool.totalBlocks - 1) ? 
                                   &g_MemPool.blocks[i+1] : NULL;
    }
}

// 预读取管理
#define PREFETCH_SIZE (1024*1024)  // 1MB预读

typedef struct _PREFETCH_BUFFER {
    BYTE* data;
    LONGLONG offset;
    DWORD size;
    DWORD readPos;
} PREFETCH_BUFFER;

static PREFETCH_BUFFER g_PrefetchBuffer;

// 初始化预读缓冲
void InitializePrefetch() {
    g_PrefetchBuffer.data = malloc(PREFETCH_SIZE);
    g_PrefetchBuffer.size = 0;
    g_PrefetchBuffer.offset = 0;
    g_PrefetchBuffer.readPos = 0;
}

// 预读取数据
BOOL PrefetchData(HANDLE handle, LONGLONG offset) {
    if (offset >= g_PrefetchBuffer.offset && 
        offset < g_PrefetchBuffer.offset + g_PrefetchBuffer.size) {
        return TRUE; // 数据已在缓冲区
    }
    
    // 异步读取下一块数据
    OVERLAPPED overlap = {0};
    overlap.Offset = (DWORD)(offset & 0xFFFFFFFF);
    overlap.OffsetHigh = (DWORD)(offset >> 32);
    
    DWORD bytesRead;
    if (!ReadFile(handle, g_PrefetchBuffer.data, PREFETCH_SIZE, 
                  &bytesRead, &overlap)) {
        return FALSE;
    }
    
    g_PrefetchBuffer.offset = offset;
    g_PrefetchBuffer.size = bytesRead;
    g_PrefetchBuffer.readPos = 0;
    return TRUE;
}

// 文件句柄缓存
#define MAX_HANDLE_CACHE 64

typedef struct _HANDLE_CACHE_ENTRY {
    WCHAR fileName[MAX_PATH];
    HANDLE handle;
    FILETIME lastAccess;
    BOOL inUse;
} HANDLE_CACHE_ENTRY;

typedef struct _HANDLE_CACHE {
    CRITICAL_SECTION lock;
    HANDLE_CACHE_ENTRY entries[MAX_HANDLE_CACHE];
    DWORD count;
} HANDLE_CACHE;

static HANDLE_CACHE g_HandleCache;

// 初始化句柄缓存
void InitializeHandleCache() {
    InitializeCriticalSection(&g_HandleCache.lock);
    g_HandleCache.count = 0;
    
    for (int i = 0; i < MAX_HANDLE_CACHE; i++) {
        g_HandleCache.entries[i].inUse = FALSE;
        g_HandleCache.entries[i].handle = INVALID_HANDLE_VALUE;
    }
}

// 从缓存获取句柄
HANDLE GetCachedHandle(LPCWSTR fileName) {
    EnterCriticalSection(&g_HandleCache.lock);
    
    for (DWORD i = 0; i < g_HandleCache.count; i++) {
        if (wcscmp(g_HandleCache.entries[i].fileName, fileName) == 0 &&
            g_HandleCache.entries[i].inUse) {
            GetSystemTimeAsFileTime(&g_HandleCache.entries[i].lastAccess);
            LeaveCriticalSection(&g_HandleCache.lock);
            return g_HandleCache.entries[i].handle;
        }
    }
    
    LeaveCriticalSection(&g_HandleCache.lock);
    return INVALID_HANDLE_VALUE;
}

// IO请求队列
#define MAX_IO_QUEUE 1024

typedef struct _IO_REQUEST {
    DWORD operation;  // READ/WRITE
    LONGLONG offset;
    DWORD length;
    LPVOID buffer;
    BOOL completed;
} IO_REQUEST;

typedef struct _IO_QUEUE {
    CRITICAL_SECTION lock;
    IO_REQUEST requests[MAX_IO_QUEUE];
    DWORD head;
    DWORD tail;
    HANDLE processThread;
} IO_QUEUE;

static IO_QUEUE g_IoQueue;

// 初始化IO队列
void InitializeIoQueue() {
    InitializeCriticalSection(&g_IoQueue.lock);
    g_IoQueue.head = g_IoQueue.tail = 0;
    g_IoQueue.processThread = CreateThread(NULL, 0, IoProcessThread, NULL, 0, NULL);
}

// IO处理线程
DWORD WINAPI IoProcessThread(LPVOID param) {
    while (TRUE) {
        EnterCriticalSection(&g_IoQueue.lock);
        
        // 合并相邻的读写请求
        MergeIoRequests();
        
        // 处理请求
        ProcessIoRequests();
        
        LeaveCriticalSection(&g_IoQueue.lock);
        Sleep(1);  // 避免CPU占用过高
    }
    return 0;
}

// 错误恢复
typedef struct _ERROR_LOG {
    DWORD errorCode;
    WCHAR fileName[MAX_PATH];
    DWORD operation;
    SYSTEMTIME time;
} ERROR_LOG;

static void LogError(DWORD errorCode, LPCWSTR fileName, DWORD operation) {
    ERROR_LOG log;
    log.errorCode = errorCode;
    wcscpy_s(log.fileName, MAX_PATH, fileName);
    log.operation = operation;
    GetSystemTime(&log.time);
    
    // 写入错误日志文件
    WriteErrorLog(&log);
    
    // 尝试自动恢复
    if (errorCode == ERROR_HANDLE_EOF ||
        errorCode == ERROR_INVALID_HANDLE) {
        RecoverFromError(&log);
    }
}

// 文件预分配管理
typedef struct _FILE_ALLOCATION {
    LONGLONG size;
    BOOL sparse;
} FILE_ALLOCATION;

// 预分配文件空间
NTSTATUS PreallocateFile(HANDLE handle, LONGLONG size, BOOL sparse) {
    if (sparse) {
        // 设置为稀疏文件
        DWORD returned;
        if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, 
                            NULL, 0, NULL, 0, &returned, NULL)) {
            return DokanNtStatusFromWin32(GetLastError());
        }
    }
    
    // 预分配空间
    FILE_ALLOCATION_INFO allocInfo;
    allocInfo.AllocationSize.QuadPart = size;
    
    if (!SetFileInformationByHandle(handle, FileAllocationInfo,
                                   &allocInfo, sizeof(allocInfo))) {
        return DokanNtStatusFromWin32(GetLastError());
    }
    
    return STATUS_SUCCESS;
}

// 压缩管理
#define COMPRESSION_BUFFER_SIZE (1024*1024)

typedef struct _COMPRESSION_CONTEXT {
    BYTE* inputBuffer;
    BYTE* outputBuffer;
    DWORD bufferSize;
    HANDLE compressThread;
} COMPRESSION_CONTEXT;

static COMPRESSION_CONTEXT g_Compression;

// 初始化压缩
void InitializeCompression() {
    g_Compression.inputBuffer = malloc(COMPRESSION_BUFFER_SIZE);
    g_Compression.outputBuffer = malloc(COMPRESSION_BUFFER_SIZE);
    g_Compression.bufferSize = COMPRESSION_BUFFER_SIZE;
    
    // 创建压缩线程
    g_Compression.compressThread = CreateThread(NULL, 0,
                                              CompressionThread, NULL, 0, NULL);
}

// 压缩数据
BOOL CompressData(LPCVOID data, DWORD size, LPVOID* compressed, LPDWORD compressedSize) {
    // 使用 Windows NTDLL RtlCompressBuffer API
    ULONG finalCompressedSize;
    NTSTATUS status = RtlCompressBuffer(
        COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM,
        (PUCHAR)data,
        size,
        (PUCHAR)*compressed,
        size,
        4096,
        &finalCompressedSize,
        malloc(0x10000)
    );
    
    if (NT_SUCCESS(status)) {
        *compressedSize = finalCompressedSize;
        return TRUE;
    }
    return FALSE;
}

// 文件分片管理
#define CHUNK_SIZE (64*1024*1024)  // 64MB分片

typedef struct _FILE_CHUNK {
    DWORD index;
    LONGLONG offset;
    DWORD size;
    WCHAR path[MAX_PATH];
} FILE_CHUNK;

typedef struct _CHUNK_MANAGER {
    CRITICAL_SECTION lock;
    FILE_CHUNK* chunks;
    DWORD chunkCount;
} CHUNK_MANAGER;

static CHUNK_MANAGER g_ChunkMgr;

// 初始化分片管理
void InitializeChunkManager() {
    InitializeCriticalSection(&g_ChunkMgr.lock);
    g_ChunkMgr.chunks = NULL;
    g_ChunkMgr.chunkCount = 0;
}

// 创建文件分片
NTSTATUS CreateFileChunks(LPCWSTR filePath, LONGLONG fileSize) {
    DWORD chunkCount = (DWORD)((fileSize + CHUNK_SIZE - 1) / CHUNK_SIZE);
    
    for (DWORD i = 0; i < chunkCount; i++) {
        WCHAR chunkPath[MAX_PATH];
        swprintf_s(chunkPath, MAX_PATH, L"%s.chunk%d", filePath, i);
        
        // 创建分片文件
        HANDLE chunkHandle = CreateFile(chunkPath, GENERIC_READ | GENERIC_WRITE,
                                      FILE_SHARE_READ, NULL, CREATE_ALWAYS,
                                      FILE_ATTRIBUTE_NORMAL, NULL);
        if (chunkHandle == INVALID_HANDLE_VALUE) {
            return DokanNtStatusFromWin32(GetLastError());
        }
        
        CloseHandle(chunkHandle);
    }
    
    return STATUS_SUCCESS;
}

// 文件访问模式管理
typedef enum _ACCESS_PATTERN {
    PATTERN_UNKNOWN,
    PATTERN_SEQUENTIAL,
    PATTERN_RANDOM,
    PATTERN_FORWARD_ONLY,
    PATTERN_REVERSE_ONLY
} ACCESS_PATTERN;

typedef struct _ACCESS_STATS {
    LONGLONG lastOffset;
    DWORD sequentialCount;
    DWORD randomCount;
    ACCESS_PATTERN pattern;
} ACCESS_STATS;

typedef struct _ACCESS_MANAGER {
    CRITICAL_SECTION lock;
    HANDLE optimizeThread;
    struct {
        WCHAR fileName[MAX_PATH];
        ACCESS_STATS stats;
    } fileStats[1024];
    DWORD fileCount;
} ACCESS_MANAGER;

static ACCESS_MANAGER g_AccessMgr;

// 初始化访问模式管理
void InitializeAccessManager() {
    InitializeCriticalSection(&g_AccessMgr.lock);
    g_AccessMgr.fileCount = 0;
    
    // 创建优化线程
    g_AccessMgr.optimizeThread = CreateThread(NULL, 0,
                                            AccessOptimizeThread, NULL, 0, NULL);
}

// 更新访问模式统计
void UpdateAccessPattern(LPCWSTR fileName, LONGLONG offset) {
    EnterCriticalSection(&g_AccessMgr.lock);
    
    // 查找或添加文件统计
    int index = -1;
    for (DWORD i = 0; i < g_AccessMgr.fileCount; i++) {
        if (wcscmp(g_AccessMgr.fileStats[i].fileName, fileName) == 0) {
            index = i;
            break;
        }
    }
    
    if (index == -1) {
        if (g_AccessMgr.fileCount < 1024) {
            index = g_AccessMgr.fileCount++;
            wcscpy_s(g_AccessMgr.fileStats[index].fileName, MAX_PATH, fileName);
            memset(&g_AccessMgr.fileStats[index].stats, 0, sizeof(ACCESS_STATS));
        }
    }
    
    if (index != -1) {
        ACCESS_STATS* stats = &g_AccessMgr.fileStats[index].stats;
        
        // 更新访问模式统计
        if (stats->lastOffset != -1) {
            if (offset == stats->lastOffset + 1)
                stats->sequentialCount++;
            else
                stats->randomCount++;
                
            // 确定访问模式
            if (stats->sequentialCount > stats->randomCount * 2)
                stats->pattern = PATTERN_SEQUENTIAL;
            else if (stats->randomCount > stats->sequentialCount * 2)
                stats->pattern = PATTERN_RANDOM;
        }
        
        stats->lastOffset = offset;
    }
    
    LeaveCriticalSection(&g_AccessMgr.lock);
}

// 文件锁定管理
typedef struct _LOCK_RANGE {
    LONGLONG offset;
    LONGLONG length;
    DWORD lockType;
} LOCK_RANGE;

typedef struct _LOCK_MANAGER {
    CRITICAL_SECTION lock;
    struct {
        WCHAR fileName[MAX_PATH];
        LOCK_RANGE* ranges;
        DWORD rangeCount;
    } fileLocks[1024];
    DWORD fileCount;
} LOCK_MANAGER;

static LOCK_MANAGER g_LockMgr;

// 初始化锁定管理
void InitializeLockManager() {
    InitializeCriticalSection(&g_LockMgr.lock);
    g_LockMgr.fileCount = 0;
}

// 检查锁定冲突
BOOL CheckLockConflict(LPCWSTR fileName, LONGLONG offset, LONGLONG length) {
    EnterCriticalSection(&g_LockMgr.lock);
    
    BOOL conflict = FALSE;
    for (DWORD i = 0; i < g_LockMgr.fileCount; i++) {
        if (wcscmp(g_LockMgr.fileLocks[i].fileName, fileName) == 0) {
            for (DWORD j = 0; j < g_LockMgr.fileLocks[i].rangeCount; j++) {
                LOCK_RANGE* range = &g_LockMgr.fileLocks[i].ranges[j];
                if (offset < range->offset + range->length &&
                    offset + length > range->offset) {
                    conflict = TRUE;
                    break;
                }
            }
            break;
        }
    }
    
    LeaveCriticalSection(&g_LockMgr.lock);
    return conflict;
}

// 文件预热管理
typedef struct _WARMUP_CONTEXT {
    WCHAR filePath[MAX_PATH];
    LONGLONG fileSize;
    DWORD priority;  // 1-10, 10最高
    BOOL loaded;
} WARMUP_CONTEXT;

typedef struct _WARMUP_MANAGER {
    CRITICAL_SECTION lock;
    WARMUP_CONTEXT* files;
    DWORD fileCount;
    HANDLE warmupThread;
    BOOL shutdownFlag;
} WARMUP_MANAGER;

static WARMUP_MANAGER g_WarmupMgr;

// 初始化预热管理器
void InitializeWarmupManager() {
    InitializeCriticalSection(&g_WarmupMgr.lock);
    g_WarmupMgr.files = malloc(sizeof(WARMUP_CONTEXT) * 1024);
    g_WarmupMgr.fileCount = 0;
    g_WarmupMgr.shutdownFlag = FALSE;
    
    // 创建预热线程
    g_WarmupMgr.warmupThread = CreateThread(NULL, 0, WarmupThread, NULL, 0, NULL);
}

// 预热线程
DWORD WINAPI WarmupThread(LPVOID param) {
    while (!g_WarmupMgr.shutdownFlag) {
        EnterCriticalSection(&g_WarmupMgr.lock);
        
        // 按优先级排序
        SortWarmupFiles();
        
        // 预热文件
        for (DWORD i = 0; i < g_WarmupMgr.fileCount; i++) {
            if (!g_WarmupMgr.files[i].loaded) {
                PreloadFile(&g_WarmupMgr.files[i]);
            }
        }
        
        LeaveCriticalSection(&g_WarmupMgr.lock);
        Sleep(1000);
    }
    return 0;
}

// 智能预测缓存
typedef struct _ACCESS_PATTERN_PREDICTOR {
    struct {
        LONGLONG offset;
        LONGLONG nextOffset;
        DWORD count;
    } patterns[256];
    DWORD patternCount;
} ACCESS_PATTERN_PREDICTOR;

typedef struct _PREDICTION_MANAGER {
    CRITICAL_SECTION lock;
    struct {
        WCHAR fileName[MAX_PATH];
        ACCESS_PATTERN_PREDICTOR predictor;
    } filePredictors[1024];
    DWORD fileCount;
} PREDICTION_MANAGER;

static PREDICTION_MANAGER g_PredictMgr;

// 初始化预测管理器
void InitializePredictionManager() {
    InitializeCriticalSection(&g_PredictMgr.lock);
    g_PredictMgr.fileCount = 0;
}

// 更新访问模式预测
void UpdateAccessPrediction(LPCWSTR fileName, LONGLONG offset) {
    EnterCriticalSection(&g_PredictMgr.lock);
    
    // 查找或添加文件预测器
    int index = FindOrAddPredictor(fileName);
    if (index != -1) {
        ACCESS_PATTERN_PREDICTOR* predictor = 
            &g_PredictMgr.filePredictors[index].predictor;
            
        // 更新模式统计
        UpdatePatternStats(predictor, offset);
        
        // 预测下一个访问位置
        LONGLONG nextOffset = PredictNextAccess(predictor);
        if (nextOffset != -1) {
            // 预读数据
            PrefetchData(GetCachedHandle(fileName), nextOffset);
        }
    }
    
    LeaveCriticalSection(&g_PredictMgr.lock);
}

// 内存压缩管理
typedef struct _MEMORY_PAGE {
    BYTE* data;
    DWORD size;
    DWORD compressedSize;
    BOOL compressed;
    DWORD accessCount;
    FILETIME lastAccess;
} MEMORY_PAGE;

typedef struct _MEMORY_COMPRESSOR {
    CRITICAL_SECTION lock;
    MEMORY_PAGE* pages;
    DWORD pageCount;
    DWORD totalMemory;
    DWORD compressedMemory;
    HANDLE compressThread;
} MEMORY_COMPRESSOR;

static MEMORY_COMPRESSOR g_MemCompressor;

// 初始化内存压缩器
void InitializeMemoryCompressor() {
    InitializeCriticalSection(&g_MemCompressor.lock);
    g_MemCompressor.pages = malloc(sizeof(MEMORY_PAGE) * 1024);
    g_MemCompressor.pageCount = 0;
    g_MemCompressor.totalMemory = 0;
    g_MemCompressor.compressedMemory = 0;
    
    // 创建压缩线程
    g_MemCompressor.compressThread = CreateThread(NULL, 0,
                                                MemoryCompressThread, NULL, 0, NULL);
}

// 页面置换算法
void SwapOutPages() {
    EnterCriticalSection(&g_MemCompressor.lock);
    
    // 按访问时间排序
    SortPagesByAccess();
    
    // 压缩最久未访问的页面
    for (DWORD i = 0; i < g_MemCompressor.pageCount; i++) {
        if (!g_MemCompressor.pages[i].compressed) {
            CompressPage(&g_MemCompressor.pages[i]);
        }
    }
    
    LeaveCriticalSection(&g_MemCompressor.lock);
}

// 异步写入管理
typedef struct _WRITE_REQUEST {
    WCHAR filePath[MAX_PATH];
    LONGLONG offset;
    BYTE* data;
    DWORD size;
    BOOL urgent;
} WRITE_REQUEST;

typedef struct _ASYNC_WRITER {
    CRITICAL_SECTION lock;
    WRITE_REQUEST* requests;
    DWORD requestCount;
    HANDLE writerThread;
    HANDLE flushEvent;
    BOOL shutdownFlag;
} ASYNC_WRITER;

static ASYNC_WRITER g_AsyncWriter;

// 初始化异步写入器
void InitializeAsyncWriter() {
    InitializeCriticalSection(&g_AsyncWriter.lock);
    g_AsyncWriter.requests = malloc(sizeof(WRITE_REQUEST) * 1024);
    g_AsyncWriter.requestCount = 0;
    g_AsyncWriter.shutdownFlag = FALSE;
    g_AsyncWriter.flushEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    // 创建写入线程
    g_AsyncWriter.writerThread = CreateThread(NULL, 0,
                                            AsyncWriterThread, NULL, 0, NULL);
}

// 添加写请求
void QueueWriteRequest(LPCWSTR filePath, LONGLONG offset,
                      LPCVOID data, DWORD size, BOOL urgent) {
    EnterCriticalSection(&g_AsyncWriter.lock);
    
    if (g_AsyncWriter.requestCount < 1024) {
        WRITE_REQUEST* req = &g_AsyncWriter.requests[g_AsyncWriter.requestCount++];
        wcscpy_s(req->filePath, MAX_PATH, filePath);
        req->offset = offset;
        req->data = malloc(size);
        memcpy(req->data, data, size);
        req->size = size;
        req->urgent = urgent;
        
        if (urgent) {
            SetEvent(g_AsyncWriter.flushEvent);
        }
    }
    
    LeaveCriticalSection(&g_AsyncWriter.lock);
}

// 系统监控管理
typedef struct _SYSTEM_STATS {
    struct {
        DWORD totalOperations;
        DWORD successOperations;
        DWORD failedOperations;
        LARGE_INTEGER totalBytes;
        DWORD avgResponseTime;
    } read, write;
    
    struct {
        DWORD totalPages;
        DWORD dirtyPages;
        DWORD compressedPages;
        DWORD cacheHits;
        DWORD cacheMisses;
    } cache;
    
    struct {
        DWORD peakMemoryUsage;
        DWORD currentMemoryUsage;
        DWORD totalAllocations;
        DWORD totalFrees;
    } memory;
} SYSTEM_STATS;

typedef struct _SYSTEM_MONITOR {
    CRITICAL_SECTION lock;
    SYSTEM_STATS stats;
    HANDLE monitorThread;
    HANDLE logFile;
    BOOL enableLogging;
} SYSTEM_MONITOR;

static SYSTEM_MONITOR g_SysMonitor;

// 初始化系统监控
void InitializeSystemMonitor() {
    InitializeCriticalSection(&g_SysMonitor.lock);
    memset(&g_SysMonitor.stats, 0, sizeof(SYSTEM_STATS));
    g_SysMonitor.enableLogging = TRUE;
    
    // 创建监控线程
    g_SysMonitor.monitorThread = CreateThread(NULL, 0,
                                            MonitorThread, NULL, 0, NULL);
    
    // 打开日志文件
    g_SysMonitor.logFile = CreateFile(L"system_monitor.log",
                                     GENERIC_WRITE,
                                     FILE_SHARE_READ,
                                     NULL,
                                     CREATE_ALWAYS,
                                     FILE_ATTRIBUTE_NORMAL,
                                     NULL);
}

// 快照管理
typedef struct _SNAPSHOT_ENTRY {
    WCHAR fileName[MAX_PATH];
    FILETIME timestamp;
    LONGLONG size;
    BYTE* metadata;
} SNAPSHOT_ENTRY;

typedef struct _SNAPSHOT_MANAGER {
    CRITICAL_SECTION lock;
    SNAPSHOT_ENTRY* entries;
    DWORD entryCount;
    WCHAR snapshotDir[MAX_PATH];
    DWORD maxSnapshots;
} SNAPSHOT_MANAGER;

// 创建文件系统快照
NTSTATUS CreateFileSystemSnapshot() {
    EnterCriticalSection(&g_SnapshotMgr.lock);
    
    // 遍历所有文件创建元数据
    WIN32_FIND_DATA findData;
    HANDLE findHandle = FindFirstFile(L"*.*", &findData);
    
    while (FindNextFile(findHandle, &findData)) {
        SNAPSHOT_ENTRY entry;
        wcscpy_s(entry.fileName, MAX_PATH, findData.cFileName);
        entry.timestamp = findData.ftLastWriteTime;
        entry.size = findData.nFileSizeLow;
        
        // 保存文件元数据
        SaveSnapshotEntry(&entry);
    }
    
    LeaveCriticalSection(&g_SnapshotMgr.lock);
    return STATUS_SUCCESS;
}

// 数据去重管理
typedef struct _CHUNK_HASH {
    BYTE hash[32];  // SHA-256 hash
    LONGLONG offset;
    DWORD size;
    DWORD refCount;
} CHUNK_HASH;

typedef struct _DEDUP_MANAGER {
    CRITICAL_SECTION lock;
    CHUNK_HASH* chunks;
    DWORD chunkCount;
    HANDLE dedupThread;
} DEDUP_MANAGER;

// 检查数据块是否重复
BOOL IsChunkDuplicate(LPCVOID data, DWORD size, CHUNK_HASH* existingChunk) {
    BYTE hash[32];
    CalculateHash(data, size, hash);
    
    for (DWORD i = 0; i < g_DedupMgr.chunkCount; i++) {
        if (memcmp(hash, g_DedupMgr.chunks[i].hash, 32) == 0) {
            *existingChunk = g_DedupMgr.chunks[i];
            return TRUE;
        }
    }
    return FALSE;
}

// 文件系统检查
typedef struct _FS_CHECK_RESULT {
    DWORD corruptedFiles;
    DWORD missingFiles;
    DWORD inconsistentMetadata;
    WCHAR* errors[1024];
    DWORD errorCount;
} FS_CHECK_RESULT;

// 执行文件系统检查
NTSTATUS CheckFileSystem(FS_CHECK_RESULT* result) {
    // 检查文件系统元数据
    CheckMetadata(result);
    
    // 检查文件完整性
    CheckFileIntegrity(result);
    
    // 检查目录结构
    CheckDirectoryStructure(result);
    
    // 检查引用计数
    CheckReferenceCount(result);
    
    // 自动修复可修复的问题
    if (result->errorCount > 0) {
        RepairFileSystem(result);
    }
    
    return STATUS_SUCCESS;
}

// 配额管理
typedef struct _QUOTA_ENTRY {
    WCHAR userName[256];
    LONGLONG maxSize;
    LONGLONG currentSize;
    DWORD maxFiles;
    DWORD currentFiles;
} QUOTA_ENTRY;

typedef struct _QUOTA_MANAGER {
    CRITICAL_SECTION lock;
    QUOTA_ENTRY* quotas;
    DWORD quotaCount;
} QUOTA_MANAGER;

// 检查配额限制
BOOL CheckQuota(LPCWSTR userName, LONGLONG size) {
    EnterCriticalSection(&g_QuotaMgr.lock);
    
    for (DWORD i = 0; i < g_QuotaMgr.quotaCount; i++) {
        if (wcscmp(g_QuotaMgr.quotas[i].userName, userName) == 0) {
            if (g_QuotaMgr.quotas[i].currentSize + size > 
                g_QuotaMgr.quotas[i].maxSize) {
                LeaveCriticalSection(&g_QuotaMgr.lock);
                return FALSE;
            }
            break;
        }
    }
    
    LeaveCriticalSection(&g_QuotaMgr.lock);
    return TRUE;
}

// 加密管理
typedef struct _ENCRYPTION_CONTEXT {
    BYTE key[32];
    BYTE iv[16];
    DWORD algorithm;  // AES-256, etc.
    BOOL enabled;
} ENCRYPTION_CONTEXT;

typedef struct _ENCRYPTION_MANAGER {
    CRITICAL_SECTION lock;
    ENCRYPTION_CONTEXT* contexts;
    DWORD contextCount;
    HANDLE cryptoProvider;
} ENCRYPTION_MANAGER;

// 加密文件数据
NTSTATUS EncryptFileData(LPVOID data, DWORD size, 
                         ENCRYPTION_CONTEXT* context) {
    // 使用Windows CryptoAPI进行加密
    HCRYPTKEY hKey;
    if (!CryptCreateKey(g_EncryptMgr.cryptoProvider, 
                        CALG_AES_256, 0, 0, 0, &hKey)) {
        return STATUS_UNSUCCESSFUL;
    }
    
    // 设置加密参数
    CryptSetKeyParam(hKey, KP_IV, context->iv, 0);
    
    // 执行加密
    if (!CryptEncrypt(hKey, 0, TRUE, 0, data, &size, size)) {
        CryptDestroyKey(hKey);
        return STATUS_UNSUCCESSFUL;
    }
    
    CryptDestroyKey(hKey);
    return STATUS_SUCCESS;
}
